﻿using System;
using System.Collections.Generic;
using System.Text;
using Wangzeran.CodeMaker.Core.Tag;
using Wangzeran.CodeMaker.PlugIns.Util;
using Wangzeran.CodeMaker.Core.Util;
using Wangzeran.CodeMaker.Core.Model;

namespace Wangzeran.CodeMaker.PlugIns.Tags
{
    /// <summary>
    /// 脚本标签
    /// </summary>
    public class ScriptTag : TagSupport
    {

        #region 属性
        /// <summary>
        /// 脚本路径
        /// </summary>
        private const string ATTR_PATH = "path";
        /// <summary>
        /// 脚本变量
        /// </summary>
        private const string ATTR_VARIABLES = "variables";
        /// <summary>
        /// 脚本返回结果
        /// </summary>
        private const string ATTR_RESULT = "result";

        #endregion


        #region 属性值

        #endregion


        public ScriptTag()
        {

        }


        /// <summary>
        /// Python脚本引擎
        /// </summary>
        private PythonScriptEngine scriptEngine;
        /// <summary>
        /// 标签名称
        /// </summary>
        public override string TagName
        {
            get { return "c:script"; }
        }

        /// <summary>
        /// 处理标签
        /// </summary>
        /// <param name="tagStr">标签文本</param>
        /// <param name="value">标签值</param>
        /// <returns></returns>
        public override string ProcessTag(string tagStr, object value)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                ProcessProperty(sb, value);
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 处理属性
        /// </summary>
        /// <param name="value">标签值</param>
        /// <returns></returns>
        private void ProcessProperty(StringBuilder sb, object value)
        {
            try
            {
                if (this.Properties.ContainsKey(ATTR_PATH)
                    && this.Properties.ContainsKey(ATTR_VARIABLES))
                {
                    string path = this.Properties[ATTR_PATH];
                    lock (CacheContainers.PythonScriptEngines)
                    {
                        if (CacheContainers.PythonScriptEngines.ContainsKey(path))
                        {
                            // 使用已有的脚本引擎
                            scriptEngine = CacheContainers.PythonScriptEngines[path];
                        }
                        else
                        {
                            // 添加新的脚本引擎
                            scriptEngine = new PythonScriptEngine();
                            CacheContainers.PythonScriptEngines.Add(path, scriptEngine);
                        }
                    }
                    //scriptEngine = new PythonScriptEngine();
                    ProcessVariables(value);
                    ProcessPath();
                    ProcessResult(sb);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            //finally
            //{
            //    scriptEngine.Dispose();
            //}
        }

        /// <summary>
        /// 处理变量
        /// </summary>
        /// <param name="value">标签值</param>
        private void ProcessVariables(object value)
        {
            try
            {
                // 获取脚本变量格式，并去掉大括号{}
                string variablesValue = Properties[ATTR_VARIABLES]
                                            .Remove(Properties[ATTR_VARIABLES].Length - 1, 1)
                                            .Remove(0, 1);
                // 变量分组
                string[] strVariable = variablesValue.Split(';');

                ITag tag = new ValueTag();
                foreach (string item in strVariable)
                {
                    // 获取键值分隔符
                    int splitIndex = item.IndexOf(":");
                    // 获取键值
                    string[] strValue = new string[2];
                    strValue[0] = item.Substring(0, splitIndex);
                    strValue[1] = item.Substring(splitIndex + 1);
                    // 把变量添加到脚本范围
                    if (StringUtil.IsTag(strValue[1]))
                    {
                        // 如果是标签则获取标签值
                        strValue[1] = tag.Process(strValue[1], value);
                    }
                    if (strValue[0] == "Columns")
                    {
                        TableModal table = value as TableModal;
                        if (table != null)
                        {
                            int length = table.Columns.Keys.Count;
                            string[] arr = new string[length];
                            int index = 0;
                            foreach (string columnName in table.Columns.Keys)
                            {
                                arr[index++] = columnName;
                            }
                            scriptEngine.AddVariable(strValue[0].Trim(), arr);
                        }
                    }
                    else
                    {
                        scriptEngine.AddVariable(strValue[0].Trim(), strValue[1].Trim());
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 处理路径
        /// </summary>
        private void ProcessPath()
        {
            try
            {
                // 执行脚本
                scriptEngine.ExecuteFile(Properties[ATTR_PATH]);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 处理脚本的返回结果
        /// </summary>
        /// <param name="sb">StringBuilder</param>
        private void ProcessResult(StringBuilder sb)
        {
            try
            {
                sb.Append(scriptEngine.GetVariable(Properties[ATTR_RESULT]).ToString());
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
